#include "crypthelper.h"
#include <QString>

#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
#include <cryptopp/hex.h>
#include <cryptopp/sha.h>
#include <cryptopp/md5.h>

#include <string>
using namespace CryptoPP;

CryptHelper::CryptHelper()
{

}

CryptHelper::~CryptHelper()
{

}

std::string CryptHelper::encrypt(const char *plainText, const std::string &sKey, const std::string &sIV, const AesMode &mode)
{
    std::string outstr;

    //填key
    SecByteBlock key(AES::MAX_KEYLENGTH);
    memset(key, 0x30, key.size());
    sKey.size() <= AES::MAX_KEYLENGTH ? memcpy(key, sKey.c_str(), sKey.size()) : memcpy(key, sKey.c_str(), AES::MAX_KEYLENGTH);

    //填iv
    byte iv[AES::BLOCKSIZE];
    memset(iv, 0x30, AES::BLOCKSIZE);
    sIV.size() <= AES::BLOCKSIZE ? memcpy(iv, sIV.c_str(), sIV.size()) : memcpy(iv, sIV.c_str(), AES::BLOCKSIZE);

    AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);

    StreamTransformation *st = NULL;

    if(mode == AesMode::ECB)
        st = new ECB_Mode_ExternalCipher::Encryption(aesEncryption);
    else if(mode == AesMode::CBC)
        st = new CBC_Mode_ExternalCipher::Encryption(aesEncryption, iv);
    else if(mode == AesMode::CBC_CTS)
        st = new CBC_CTS_Mode_ExternalCipher::Encryption(aesEncryption, iv);
    else if(mode == AesMode::CFB)
        st = new CFB_Mode_ExternalCipher::Encryption(aesEncryption, iv);
    else if(mode == AesMode::OFB)
        st = new OFB_Mode_ExternalCipher::Encryption(aesEncryption, iv);
    else if(mode == AesMode::CTR)
        st = new CTR_Mode_ExternalCipher::Encryption(aesEncryption, iv);

    StreamTransformationFilter encryptor(*st, new HexEncoder(new StringSink(outstr)));
    encryptor.Put((byte *)plainText, strlen(plainText));
    encryptor.MessageEnd();

    delete st;
    return outstr;
}

std::string CryptHelper::decrypt(const char *cipherText, const std::string &sKey, const std::string &sIV, const AesMode &mode)
{
    std::string outstr;

    //填key
    SecByteBlock key(AES::MAX_KEYLENGTH);
    memset(key, 0x30, key.size());
    sKey.size() <= AES::MAX_KEYLENGTH ? memcpy(key, sKey.c_str(), sKey.size()) : memcpy(key, sKey.c_str(), AES::MAX_KEYLENGTH);

    //填iv
    byte iv[AES::BLOCKSIZE];
    memset(iv, 0x30, AES::BLOCKSIZE);
    sIV.size() <= AES::BLOCKSIZE ? memcpy(iv, sIV.c_str(), sIV.size()) : memcpy(iv, sIV.c_str(), AES::BLOCKSIZE);

    StreamTransformation *st = NULL;

    if(mode == AesMode::ECB)
        st = new ECB_Mode<AES >::Decryption((byte *)key, AES::MAX_KEYLENGTH);
    else if(mode == AesMode::CBC)
        st = new CBC_Mode<AES >::Decryption((byte *)key, AES::MAX_KEYLENGTH, iv);
    else if(mode == AesMode::CBC_CTS)
        st = new CBC_CTS_Mode<AES >::Decryption((byte *)key, AES::MAX_KEYLENGTH, iv);
    else if(mode == AesMode::CFB)
        st = new CFB_Mode<AES >::Decryption((byte *)key, AES::MAX_KEYLENGTH, iv);
    else if(mode == AesMode::OFB)
        st = new OFB_Mode<AES >::Decryption((byte *)key, AES::MAX_KEYLENGTH, iv);
    else if(mode == AesMode::CTR)
        st = new CTR_Mode<AES >::Decryption((byte *)key, AES::MAX_KEYLENGTH, iv);

    HexDecoder decryptor(new StreamTransformationFilter(*st, new StringSink(outstr)));
    decryptor.Put((byte *)cipherText, strlen(cipherText));
    decryptor.MessageEnd();

    delete st;
    return outstr;
}
